using System;
using System.Collections.Generic;
using System.Text;

namespace Storage.Core
{
	internal class PlainEntity : IEquatable<PlainEntity>, IBinarySerializable
	{
		public PlainEntity(Guid id, string type, byte[] body)
		{
			Id = id;
			Type = type;
			Body = body;
		}

		public int EstimatedSerializedSize()
		{
			// Id (16 bytes) + body (byte[] with len) + string in UTF8 with len
			return 16 + 4 + Encoding.UTF8.GetMaxByteCount(Type.Length) + 4 + Body.Length;
		}

		public void Serialize(IBinarySerializer serializer)
		{
			serializer.Write(Id).Write(Type).Write(Body);
		}

		public static PlainEntity Deserialize(IBinaryDeserializer ds)
		{
			return new PlainEntity(ds.ReadGuid(), ds.ReadString(), ds.ReadByteArray());
		}

		public static void SerializeList(IList<PlainEntity> list, IBinarySerializer serializer)
		{
			serializer.Write(list.Count);
			foreach (var plainEntity in list)
				plainEntity.Serialize(serializer);
		}

		public static List<PlainEntity> DeserializeList(IBinaryDeserializer ds)
		{
			var result = new List<PlainEntity>();
			int count = ds.ReadInt32();
			if (count <= 0)
				return result;
			for (int i = 0; i < count; i++)
				result.Add(Deserialize(ds));
			return result;
		} 

		public Guid Id { get; private set; }
		public string Type { get; private set; }
		public byte[] Body { get; private set; }

		#region Equality members
		public bool Equals(PlainEntity other)
		{
			if (ReferenceEquals(null, other)) return false;
			if (ReferenceEquals(this, other)) return true;
			return other.Id.Equals(Id)
			       && Equals(other.Type, Type)
			       && other.Body.IsEqual(Body);
		}

		public override bool Equals(object obj)
		{
			if (ReferenceEquals(null, obj)) return false;
			if (ReferenceEquals(this, obj)) return true;
			if (obj.GetType() != typeof(PlainEntity)) return false;
			return Equals((PlainEntity)obj);
		}

		public override int GetHashCode()
		{
			unchecked
			{
				int result = Id.GetHashCode();
				result = (result * 397) ^ (Type != null ? Type.GetHashCode() : 0);
				result = (result * 397) ^ (Body != null ? Body.GetHashCode() : 0);
				return result;
			}
		}

		public static bool operator ==(PlainEntity left, PlainEntity right) { return Equals(left, right); }
		public static bool operator !=(PlainEntity left, PlainEntity right) { return !Equals(left, right); } 
		#endregion
	}
}